package net.alteiar.ui.algorithms;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.PixelGrabber;

import net.alteiar.Array2D;
import net.alteiar.algorithms.Sobel;
import net.alteiar.images.BasicImage;
import net.alteiar.images.IDrawable;

public class AlgorithmEdgeDetectorSobel implements Algorithm {

	private int threshold;

	public AlgorithmEdgeDetectorSobel() {
		threshold = 5;
	}

	public void setThreshold(int threshold) {
		this.threshold = threshold;
	}

	public int getThreshold() {
		return threshold;
	}

	@Override
	public IDrawable execute(BasicImage img) {
		return new BasicImage(processImage(img, threshold));
	}

	@Override
	public String toString() {
		return "Edge detector Sobel";
	}

	public int getNeighbor(Array2D array, int color, int x, int y, int dist) {
		int blackCount = 0;

		int xBegin = Math.max(0, x - dist);
		int yBegin = Math.max(0, y - dist);

		int xEnd = Math.min(array.getWidth() - 1, x + dist);
		int yEnd = Math.min(array.getHeight() - 1, y + dist);

		for (int xCurrent = xBegin; xCurrent <= xEnd; ++xCurrent) {
			for (int yCurrent = yBegin; yCurrent <= yEnd; ++yCurrent) {
				blackCount += array.get(xCurrent, yCurrent) == color ? 1 : 0;
			}
		}

		return blackCount;
	}

	public int[] doNeighbours(int[] colors, int width) {
		Array2D result = new Array2D(colors, width);
		Array2D array = new Array2D(colors, width);

		int white = 0xffffffff;
		for (int x = 0; x < array.getWidth(); ++x) {
			for (int y = 0; y < array.getHeight(); ++y) {
				if (array.get(x, y) != white) {
					int blackCount = getNeighbor(array, white, x, y, 2);

					if (blackCount > 10) {
						result.set(x, y, Color.WHITE.getRGB());
					}
				}

				if (array.get(x, y) == white) {
					int blackCount = getNeighbor(array, white, x, y, 2);

					if (blackCount < 10) {
						result.set(x, y, Color.BLACK.getRGB());
					}
				}
			}
		}

		return result.getArray();
	}

	public int[] threshold(int[] original, int value) {
		for (int x = 0; x < original.length; x++) {
			if ((original[x] & 0xff) >= value)
				original[x] = 0xffffffff;
			else
				original[x] = 0xff000000;
		}
		return original;
	}

	private BufferedImage processImage(BasicImage img, final int threshold) {

		BufferedImage org = img.getImage();

		final int width = org.getWidth();
		final int height = org.getHeight();

		final int[] orig = new int[width * height];
		PixelGrabber grabber = new PixelGrabber(org, 0, 0, width, height, orig,
				0, width);
		try {
			grabber.grabPixels();
		} catch (InterruptedException e2) {
			System.out.println("error: " + e2);
		}

		final Sobel edgedetector = new Sobel();
		edgedetector.init(orig, width, height);
		int[] res = edgedetector.process();
		res = threshold(res, threshold);
		res = doNeighbours(res, width);
		res = doNeighbours(res, width);
		res = doNeighbours(res, width);
		res = doNeighbours(res, width);
		res = doNeighbours(res, width);
		res = doNeighbours(res, width);
		BufferedImage result = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_ARGB);

		int[] intImage = ((DataBufferInt) result.getRaster().getDataBuffer())
				.getData();

		System.arraycopy(res, 0, intImage, 0, res.length);

		return result;
	}
}
